using System;
using System.Collections;
using System.Collections.Generic;

namespace Atomic.Libraries
{
	/*/// <summary>
	/// Wrapper class to provide equality operators to (preferably immutable or short lived) enumerations.
	/// </summary>
	[Serializable]
	public class EquatableEnumerable<T> : IEquatable<EquatableEnumerable<T>>, IEnumerable<T>
	{
		private IEnumerable<T> items;
		[NonSerialized] private int hashCode;

		public EquatableEnumerable(IEnumerable<T> items)
		{
			if (items == null)
			{
				throw new ArgumentNullException();
			}

			this.items = items;
		}

		public override bool Equals(object other)
		{
			return Equals(other as EquatableEnumerable<T>);
		}

		public bool Equals(EquatableEnumerable<T> other)
		{
			return this == other;
		}
		
		public override int GetHashCode()
		{
			if (hashCode == 0)
			{
				hashCode = 23;
				unchecked
				{
					foreach (T item in items)
					{
						hashCode = hashCode * 31 + item.GetHashCode();
					}
				}
			}

			return hashCode;
		}

		private bool TryGetCount(out int count)
		{
			if (items is ICollection<T>)
			{
				count = ((ICollection<T>)items).Count;
				return true;
			}

			if (items is Array)
			{
				count = ((Array)items).Length;
				return true;
			}

			if (items is ReadOnlyList<T>)
			{
				count = ((ReadOnlyList<T>)items).Count;
				return true;
			}

			// Signal unknown count.
			count = -1;
			return false;
		}

		public IEnumerator<T> GetEnumerator()
		{
			return items.GetEnumerator();
		}
		
		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		public static bool operator ==(SymmetricEquatableEnumerable<T> object1, SymmetricEquatableEnumerable<T> object2)
		{
			if (object.ReferenceEquals(object1, object2))
			{
				// Important special case where the references are identical.
				return true;
			}

			if (object.ReferenceEquals(object1, null) || object.ReferenceEquals(object2, null))
			{
				// Case where both are null is already handled above.
				return false;
			}

			if (object1.GetType() != object2.GetType())
			{
				// For derived types. Must be the same type.
				return false;
			}
			
			if (object1.hashCode != 0 && object2.hashCode != 0 && object1.hashCode != object2.hashCode)
			{
				// Can't be equal if hash codes are computed and are different.
				return false;
			}

			int n1, n2;
			if (object1.TryGetCount(out n1) && object2.TryGetCount(out n2) && n1 != n2)
			{
				// Both inner enumerables were collections and had different counts.
				return false;
			}

			LinkedList<T> items = new LinkedList<T>();

			// Count multiplicity of instances of each item from object1.
			foreach (T item in object1.items)
			{
				items.AddAfter(item);
			}

			// Verify the same number of instances of each item from object2.
			foreach (T item in object2.items)
			{
				if (object.ReferenceEquals(item, items.First))
				{
					return true;
				}

				if (object.ReferenceEquals(item, null) || object.ReferenceEquals(items.First, null))
				{
					return false;
				}

				if (!item.Equals(items.First))
				{
					return false;
				}

				items.RemoveFirst();
			}

			return true;
		}

		public static bool operator !=(SymmetricEquatableEnumerable<T> object1, SymmetricEquatableEnumerable<T> object2)
		{
			return !(object1 == object2);
		}
	}*/
}
